package modele;

import java.util.TreeMap;

import logs.LogLevelEnum;
import logs.LogTypesEnum;
import modele.agent.AgentConway;
import modele.agent.Agents;
import modele.agent.interfaces.AgentInterface;
import modele.cases.CaseConway;
import modele.cases.Cases;
import modele.cases.interfaces.CaseAbstract;
import modele.cases.interfaces.CasesInterface;
import modele.interfaces.SimulationAbstract;
import modele.parameters.SimulParametersNames;
import controler.interfaces.StepReportInterface;

public class SimulationConway extends SimulationAbstract {

	private CasesInterface cases;
	private int nbAlive;
	TreeMap<Integer, Boolean> mapBoo;
	SimulDynamicDataInterface dynamicData;

	public SimulationConway(String simName) {
		this.simName = simName;
	}

	@Override
	protected void innerInit() {
		super.innerInit();
		mapBoo = new TreeMap<Integer, Boolean>();
		agents = new Agents();
		dynamicData = new SimulDynamicData();
		int maxX = Integer.valueOf(params.read(SimulParametersNames.NBCASEX));
		int maxY = Integer.valueOf(params.read(SimulParametersNames.NBCASEY));
		int nbTotCases = maxX * maxY;
		cases = new Cases(maxX, maxY);

		int i = 0;
		for (int x = 1; x <= maxX; x++) {
			for (int y = 1; y <= maxY; y++) {
				i++;
				if (i <= nbTotCases) {
					Float bornProb = Float.valueOf(params.read(SimulParametersNames.AGBORNPROB));
					AgentInterface ag = new AgentConway(i, bornProb);
					agents.put(i, ag);
					CaseAbstract cas = new CaseConway(x, y, ag);
					cases.put(i, cas);
					System.out.println("x: " + x + ", y: " + y);
				} else
					break;
			}
		}
		for (CaseAbstract cas : cases.getCases()) {
			int x = cas.getX();
			int y = cas.getY();
			CaseAbstract vois1 = cases.get(x - 1, y - 1);
			CaseAbstract vois2 = cases.get(x, y - 1);
			CaseAbstract vois3 = cases.get(x + 1, y - 1);
			CaseAbstract vois4 = cases.get(x - 1, y);
			CaseAbstract vois5 = cases.get(x + 1, y);
			CaseAbstract vois6 = cases.get(x - 1, y + 1);
			CaseAbstract vois7 = cases.get(x, y + 1);
			CaseAbstract vois8 = cases.get(x + 1, y + 1);
			cas.giveNeighbour(1, vois1);
			cas.giveNeighbour(2, vois2);
			cas.giveNeighbour(3, vois3);
			cas.giveNeighbour(4, vois4);
			cas.giveNeighbour(5, vois5);
			cas.giveNeighbour(6, vois6);
			cas.giveNeighbour(7, vois7);
			cas.giveNeighbour(8, vois8);
		}
		dynamicData.load(SimulDynDataNames.CASES, cases);
	}

	@Override
	protected void doStep() {
		stepsNbElapsed++;
		for (AgentInterface agent : agents.getAgents()) {
			agent.doStep();
		}
		nbAlive = 0;
		for (AgentInterface agent : agents.getAgents()) {
			agent.finalizeStep();
			if (agent.isAlive()) {
				nbAlive++;
			}
		}
		reportEndOfStep();
	}

	@Override
	public void reportEndOfStep() {
		StepReportInterface stepReport = new StepReport();
		mapBoo.clear();
		for (AgentInterface agent : agents.getAgents()) {
			mapBoo.put(agent.getId(), agent.isAlive());
		}
		stepReport.add(StepDataNames.AGENTSALIVEBOO, mapBoo);
		stepReport.add(StepDataNames.STEPNB, stepsNbElapsed);
		stepReport.add(StepDataNames.NBALIVE, nbAlive);
		controler.aknowledgeEndOfStep(stepReport);
	}

	@Override
	protected void logSteps() {
		String log = " (" + this.getName() + ") " + "Step " + stepsNbElapsed + ": " + nbAlive + " alives";
		log(LogLevelEnum.INFO, LogTypesEnum.Simul, log);
	}

	@Override
	public SimulDynamicDataInterface getDynamicData() {
		return dynamicData;
	}

}
